//
//  ObservableCreateViewController.swift
//  iOS-RxSwift-Tutorials_Example
//
//  Created by mengru.tian on 2020/9/17.
//  Copyright © 2020 CocoaPods. All rights reserved.
//

import UIKit
import RxSwift

// 1.Observable - 可监听序列
class ObservableCreateViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "Observable - 可监听序列"
        self.view.backgroundColor = UIColor.white
    }
    
    private let disposeBag = DisposeBag()
    
    // MARK: - Create Methods

    // 该方法通过传入一个默认值来初始化。
    func testJust() throws {
        
        let observable = Observable<Int>.just(5)
        subscribe(observable: observable)
    }
    
    // 该方法可以接受可变数量的参数（必需要是同类型的）
    func testOf() throws {
        
        let observable = Observable.of("A", "B", "C")
        subscribe(observable: observable)
    }
    
    // 该方法需要一个数组参数
    func testFrom() throws {
        
        let observable = Observable.from(["A", "B", "C"])
        subscribe(observable: observable)
    }
    
    // 该方法创建一个空内容的 Observable 序列
    func testEmpty() throws {
        
        let observable = Observable<Int>.empty()
        subscribe(observable: observable)
    }
    
    // 该方法创建一个永远不会发出 Event（也不会终止）的 Observable 序列。
    func testNever() throws {
        
        let observable = Observable<Int>.never()
        subscribe(observable: observable)
    }
    
    // 该方法创建一个不做任何操作，而是直接发送一个错误的 Observable 序列。
    func testError() throws {
    
        enum MyError: Error {
            case A
            case B
        }
        
        let observable = Observable<Int>.error(MyError.A)
        subscribe(observable: observable)
    }

    // 该方法通过指定起始和结束数值，创建一个以这个范围内所有值作为初始值的 Observable 序列，效果同上
    func testRange() throws {
        _ = Observable.of(1, 2, 3 ,4 ,5)
        
        let observable = Observable.range(start: 1, count: 5)
        subscribe(observable: observable)
    }
    
    // 该方法创建一个可以无限发出给定元素的 Event 的 Observable 序列（永不终止）。
    func testRepeatElement() throws {
        
         _ = Observable.repeatElement(1)
    }
    
    // 该方法创建一个只有当提供的所有的判断条件都为 true 的时候，才会给出动作的 Observable 序列。
    // 下面样例中，两种方法创建的 Observable 序列都是一样的
    func testGenerate() {
        
        let observable = Observable.generate(
            initialState: 0,
            condition: { $0 <= 10 },
            iterate: { $0 + 2 }
        )
        let observable2 = Observable.of(0 ,2 ,4 ,6 ,8 ,10)
        subscribe(observable: observable)
        subscribe(observable: observable2)
    }
    
    // 该方法接受一个 block 形式的参数，任务是对每一个过来的订阅进行处理。
    func testCreate() {
        
        // 这个block有一个回调参数observer就是订阅这个Observable对象的订阅者
        // 当一个订阅者订阅这个Observable对象的时候，就会将订阅者作为参数传入这个block来执行一些内容
        let observable = Observable<String>.create{observer in
            // 对订阅者发出了.next事件，且携带了一个数据"hangge.com"
            observer.onNext("hangge.com")
            // 对订阅者发出了.completed事件
            observer.onCompleted()
            // 因为一个订阅行为会有一个Disposable类型的返回值，所以在结尾一定要returen一个Disposable
            return Disposables.create()
        }
         
        // 订阅测试
        subscribe(observable: observable)
    }
    
    // 该个方法相当于是创建一个 Observable 工厂，通过传入一个 block 来执行延迟 Observable 序列创建的行为，而这个 block 里就是真正的实例化序列对象的地方。
    func testDeferred() throws {
        // 用于标记是奇数、还是偶数
        var isOdd = true
         
        // 使用deferred()方法延迟Observable序列的初始化，通过传入的block来实现Observable序列的初始化并且返回。
        let factory : Observable<Int> = Observable.deferred {
             
            // 让每次执行这个block时候都会让奇、偶数进行交替
            isOdd = !isOdd
             
            // 根据isOdd参数，决定创建并返回的是奇数Observable、还是偶数Observable
            if isOdd {
                return Observable.of(1, 3, 5 ,7)
            }else {
                return Observable.of(2, 4, 6, 8)
            }
        }
         
        // 第1次订阅测试
        factory.subscribe { event in
            print("isOdd:\(isOdd)", event)
        }.disposed(by: disposeBag)
         
        // 第2次订阅测试
        factory.subscribe { event in
            print("isOdd:\(isOdd)", event)
        }.disposed(by: disposeBag)
    }
    
    // 这个方法创建的 Observable 序列每隔一段设定的时间，会发出一个索引数的元素。而且它会一直发送下去。
    // 下面方法让其每 1 秒发送一次，并且是在主线程（MainScheduler）发送。
    func testInterval() throws {
        
        let observable = Observable<Int>.interval(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance).map { "当前索引数：\($0 )"}.take(5)
        observable.subscribe {
            print($0)
        }.disposed(by: disposeBag)
    }
    
    // 这个方法有两种用法，一种是创建的 Observable 序列在经过设定的一段时间后，产生唯一的一个元素。
    func testTimer() throws {
        
        // 5秒种后发出唯一的一个元素0
        let observable = Observable<Int>.timer(RxTimeInterval.seconds(5), period: RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
        observable.subscribe {
            print($0)
        }.disposed(by: disposeBag)
    }
    
    // MARK: - Private Methods
    
    // 订阅测试
    private func subscribe<T>(observable: Observable<T>) {
        observable.subscribe {
            print($0)
        }.disposed(by: disposeBag)
    }

}
